#include <cmath>
#include <iostream>
#include <QVBoxLayout>
#include <QFileDialog>
#include <QDir>
#include <QSize>
#include <QSizePolicy>
#include "Panel.hpp"
#include "Drawing.hpp"

Panel::Panel(QWidget *parent) :
	QWidget(parent)
{
	QVBoxLayout *vbox;
	QHBoxLayout *box;
	vbox = new QVBoxLayout();

	file = new QGroupBox("File");
	vbox->addWidget(file);
	box = new QHBoxLayout;
	name = new QLabel("Name:");
	name->setFixedWidth(200);
	box->addWidget(name);
	open = new QPushButton("Open...");
	open->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
	box->addWidget(open);
	file->setLayout(box);

	front = new QGroupBox("Direction");
	vbox->addWidget(front);
	box = new QHBoxLayout;
	cw = new QRadioButton("Clockwise");
	box->addWidget(cw);
	ccw = new QRadioButton("Counter-Clockwise");
	box->addWidget(ccw);
	ccw->setChecked(true);
	front->setLayout(box);
	front->setEnabled(false);

	view = new QGroupBox("Primitive");
	vbox->addWidget(view);
	box = new QHBoxLayout;
	point = new QRadioButton("Point");
	box->addWidget(point);
	frame = new QRadioButton("Frame");
	box->addWidget(frame);
	solid = new QRadioButton("Solid");
	box->addWidget(solid);
	frame->setChecked(true);
	view->setLayout(box);
	view->setEnabled(false);

	color = new QGroupBox("Color");
	vbox->addWidget(color);
	box = new QHBoxLayout;
	red = new QSpinBox();
	red->setPrefix("R = ");
	red->setRange(0, 255);
	red->setValue(255);
	red->setSingleStep(5);
	box->addWidget(red);
	green = new QSpinBox();
	green->setPrefix("G = ");
	green->setRange(0, 255);
	green->setValue(255);
	green->setSingleStep(5);
	box->addWidget(green);
	blue = new QSpinBox();
	blue->setPrefix("B = ");
	blue->setRange(0, 255);
	blue->setValue(255);
	blue->setSingleStep(5);
	box->addWidget(blue);
	color->setLayout(box);
	color->setEnabled(false);

	trans = new QGroupBox("Translation");
	vbox->addWidget(trans);
	box = new QHBoxLayout;
	movx = new QDoubleSpinBox();
	movx->setPrefix("X = ");
	box->addWidget(movx);
	movy = new QDoubleSpinBox();
	movy->setPrefix("Y = ");
	box->addWidget(movy);
	movz = new QDoubleSpinBox();
	movz->setPrefix("Z = ");
	box->addWidget(movz);
	trans->setLayout(box);
	trans->setEnabled(false);

	rotat = new QGroupBox("Rotate");
	vbox->addWidget(rotat);
	box = new QHBoxLayout;
	rotx = new QDoubleSpinBox();
	rotx->setPrefix("X = ");
	rotx->setRange(0, 360);
	rotx->setSingleStep(5);
	rotx->setWrapping(true);
	box->addWidget(rotx);
	roty = new QDoubleSpinBox();
	roty->setPrefix("Y = ");
	roty->setRange(0, 360);
	roty->setSingleStep(5);
	roty->setWrapping(true);
	box->addWidget(roty);
	rotz = new QDoubleSpinBox();
	rotz->setPrefix("Z = ");
	rotz->setRange(0, 360);
	rotz->setSingleStep(5);
	rotz->setWrapping(true);
	box->addWidget(rotz);
	rotat->setLayout(box);
	rotat->setEnabled(false);

	QHBoxLayout *hbox = new QHBoxLayout;
	vbox->addLayout(hbox);
	clip = new QGroupBox("Clipping");
	hbox->addWidget(clip);
	box = new QHBoxLayout;
	nearer = new QDoubleSpinBox();
	nearer->setPrefix("Near = ");
	nearer->setRange(0, 255);
	box->addWidget(nearer);
	farer = new QDoubleSpinBox();
	farer->setPrefix("Far = ");
	farer->setRange(0, 255);
	box->addWidget(farer);
	clip->setLayout(box);
	clip->setEnabled(false);

	reset = new QPushButton("Reset\nCamera");
	reset->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
	reset->setEnabled(false);
	hbox->addWidget(reset);

	setLayout(vbox);

	sigmap = new QSignalMapper;
	connect(sigmap, SIGNAL(mapped(QString)), this, SLOT(getvalue(QString)));
	connect(open, SIGNAL(clicked()), this, SLOT(openfile()));
	connect(cw, SIGNAL(clicked()), sigmap, SLOT(map()));
	connect(ccw, SIGNAL(clicked()), sigmap, SLOT(map()));
	connect(point, SIGNAL(clicked()), sigmap, SLOT(map()));
	connect(frame, SIGNAL(clicked()), sigmap, SLOT(map()));
	connect(solid, SIGNAL(clicked()), sigmap, SLOT(map()));
	connect(red, SIGNAL(valueChanged(int)), sigmap, SLOT(map()));
	connect(green, SIGNAL(valueChanged(int)), sigmap, SLOT(map()));
	connect(blue, SIGNAL(valueChanged(int)), sigmap, SLOT(map()));
	connect(movx, SIGNAL(valueChanged(double)), sigmap, SLOT(map()));
	connect(movy, SIGNAL(valueChanged(double)), sigmap, SLOT(map()));
	connect(movz, SIGNAL(valueChanged(double)), sigmap, SLOT(map()));
	connect(rotx, SIGNAL(valueChanged(double)), sigmap, SLOT(map()));
	connect(roty, SIGNAL(valueChanged(double)), sigmap, SLOT(map()));
	connect(rotz, SIGNAL(valueChanged(double)), sigmap, SLOT(map()));
	connect(nearer, SIGNAL(valueChanged(double)), sigmap, SLOT(map()));
	connect(farer, SIGNAL(valueChanged(double)), sigmap, SLOT(map()));
	connect(reset, SIGNAL(clicked()), this, SLOT(resetpara()));

	sigmap->setMapping(cw, "struct");
	sigmap->setMapping(ccw, "struct");
	sigmap->setMapping(point, "struct");
	sigmap->setMapping(frame, "struct");
	sigmap->setMapping(solid, "struct");
	sigmap->setMapping(red, "color");
	sigmap->setMapping(green, "color");
	sigmap->setMapping(blue, "color");
	sigmap->setMapping(movx, "trans");
	sigmap->setMapping(movy, "trans");
	sigmap->setMapping(movz, "trans");
	sigmap->setMapping(rotx, "rotat");
	sigmap->setMapping(roty, "rotat");
	sigmap->setMapping(rotz, "rotat");
	sigmap->setMapping(nearer, "clip");
	sigmap->setMapping(farer, "clip");
}

void Panel::openfile()
{
	QString filename = QFileDialog::getOpenFileName(this, "Open File ...", QDir::currentPath(), "Input (*.in);;All (*.*)");
	if(filename.isNull())
		return;
	QString labeltxt = "Name: " + filename.section('/', -1);
	QFontMetrics metrics(name->font());
	QString shortlabel = metrics.elidedText(labeltxt, Qt::ElideRight, name->width());
	name->setText(shortlabel);
	emit setfilename(filename.toStdString().c_str());
}

inline double min3(double x, double y, double z)
{
	x = x < y ? x : y;
	return x < z ? x : z;
}

inline double step(double r)
{
	return floor(r) / 50;
}

void Panel::initpara(double movxmin, double movxmax, double movymin, double movymax,
					 double movzmin, double movzmax, double nearmin, double farmax)
{
	reset->setEnabled(true);
	front->setEnabled(true);
	view->setEnabled(true);
	color->setEnabled(true);
	trans->setEnabled(true);
	rotat->setEnabled(true);
	clip->setEnabled(true);
	movx->setRange(movxmin, movxmax);
	movy->setRange(movymin, movymax);
	movz->setRange(movzmin, movzmax);
	movx->setSingleStep(step(min3(movxmax - movxmin, movymax - movymin, movzmax - movzmin)));
	movy->setSingleStep(step(min3(movxmax - movxmin, movymax - movymin, movzmax - movzmin)));
	movz->setSingleStep(step(min3(movxmax - movxmin, movymax - movymin, movzmax - movzmin)));
	nearer->setRange(nearmin, farmax);
	farer->setRange(nearmin, farmax);
	nearer->setSingleStep(step(farmax - nearmin));
	farer->setSingleStep(step(farmax - nearmin));
	getvalue("struct");
	getvalue("color");
	resetpara();
}

void Panel::resetpara()
{
	movx->setValue(0);
	movy->setValue(0);
	movz->setValue(0);
	rotx->setValue(0);
	roty->setValue(0);
	rotz->setValue(0);
	nearer->setValue(nearer->minimum());
	farer->setValue(farer->maximum());
	getvalue("trans");
	getvalue("rotat");
	getvalue("rotat");
	getvalue("clip");
	emit resetcam();
}

void Panel::getvalue(const QString &v)
{
	if(v == "struct")
		emit setstruct(cw->isChecked(), 'p' * point->isChecked() + 'f' * frame->isChecked() + 's' * solid->isChecked());
	else if(v == "color")
		emit setcolor(red->value(), green->value(), blue->value());
	else if(v == "trans")
		emit settrans(movx->value(), movy->value(), movz->value());
	else if(v == "rotat")
		emit setrotat(rotx->value(), roty->value(), rotz->value());
	else if(v == "clip"){
		nearer->setMaximum(farer->value());
		farer->setMinimum(nearer->value());
		emit setclip(nearer->value(), farer->value());
	}else
		std::cerr << "Panel::getvalue(): Unknown value " << v.toStdString() << std::endl;
}
